using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace needle.UI.Controls.Flat.Windows.Forms
{
	[ProvideProperty( "MenuImage", typeof(Component)) ]
	[DefaultProperty("ImageList")]
	internal class MenuImageHelper : Component, IExtenderProvider
	{
		#region Private Attributes
		
		const int IMAGE_BUFFER = 25 ;
		const int SHORTCUT_RIGHTBUFFER = 10 ;
		const int SHORTCUT_BUFFER = 25 ;
		int IMAGE_WIDTH = SystemInformation.SmallIconSize.Width ;
		int IMAGE_HEIGHT = SystemInformation.SmallIconSize.Height ;
		
		Hashtable _hashTable = new Hashtable( );
		
		ImageList _imageList = null;
		
		#endregion
		
		#region Constructors

		public MenuImageHelper(System.ComponentModel.IContainer container)
		{
			container.Add(this);
		}
		
		public MenuImageHelper()
		{
		}

		#endregion
		
		#region Public Members

		public void SetMenuImage( Component component, string indexValue )
		{
			if (indexValue != null)
				if ( indexValue.Length > 0 )
				{
					uint imageIndex = Convert.ToUInt16(indexValue, CultureInfo.CurrentCulture);
				}
			
			if ( _hashTable.Contains( component ) != true)
			{
				_hashTable.Add( component, indexValue ) ;
				MenuItem menuItem = (MenuItem) component ;
				
				menuItem.OwnerDraw = true ;

				menuItem.MeasureItem += new MeasureItemEventHandler( OnMeasureItem ) ;
				menuItem.DrawItem  += new DrawItemEventHandler( OnDrawItem ) ;
			}
			else 
			{
				_hashTable [ component ] = indexValue ;
			}
		}

		public string GetMenuImage( Component component )
		{
			if( _hashTable.Contains( component ))
				return (string) _hashTable[ component ] ;

			return null;
		}

		public bool CanExtend( object component )
		{
			if ( component is MenuItem )
			{
				MenuItem menuItem = (MenuItem) component ;
				return ! (  menuItem.Parent is MainMenu ) ;
			}
				
			return false ;
		}

		public ImageList ImageList
		{
			get{ return _imageList ;  }
			set{ _imageList = value; }
		}
		
		#endregion

		#region Private Members/Helpers

		private int GetMenuImageIndex( Object sender )
		{
			string menuImageValue = this.GetMenuImage( sender as Component ) ;

			if ( _imageList != null)
				if ( menuImageValue != null )
					if ( menuImageValue.Length >= 0 )
					{
						int imageIndex = Convert.ToInt32( menuImageValue, CultureInfo.CurrentCulture ) ;
						if ( imageIndex >= 0 && imageIndex < _imageList.Images.Count )
							return imageIndex ;
					}

			return -1 ;
		}

		private void OnMeasureItem( Object sender, MeasureItemEventArgs e )
		{
			MenuItem menuItem = (MenuItem) sender ;
			MenuHelper menuHelper = new MenuHelper( menuItem, e.Graphics, _imageList ) ;

			e.ItemHeight = menuHelper.CalcHeight() ;
			e.ItemWidth = menuHelper.CalcWidth() ;
		}
		
		private void OnDrawItem( Object sender, DrawItemEventArgs e )
		{
			MenuItem menuItem = (MenuItem) sender ;
			MenuHelper menuHelper = new MenuHelper( menuItem, e.Graphics, _imageList ) ;
			
			bool menuSelected = (e.State & DrawItemState.Selected) > 0 ;
			menuHelper.DrawBackground( e.Bounds, menuSelected ) ;

			if ( menuHelper.IsSeperator() == true )
				menuHelper.DrawSeperator( e.Bounds ) ;
			else
			{
				int imageIndex = this.GetMenuImageIndex( sender ) ;
				menuHelper.DrawMenu( e.Bounds, menuSelected, imageIndex ) ;
			}
		}
		
		#endregion
		
		#region MenuHelper Class
		
		private class MenuHelper
		{
			
			#region Private Attributes
			
			private const int SEPERATOR_HEIGHT = 8 ;
			private const int SBORDER_WIDTH = 1 ;
			private const int BORDER_SIZE = SBORDER_WIDTH * 2 ;
			private const int SBUFFER_WIDTH = 5 ;
			private const int LBUFFER_WIDTH = 15 ;
			private const int SHORTCUT_BUFFER_SIZE = 20 ;
			private const int ARROW_WIDTH = 15 ;
			private int IMAGE_WIDTH = SystemInformation.SmallIconSize.Width ;
			private int IMAGE_HEIGHT = SystemInformation.SmallIconSize.Height ;
			private int IMAGE_BUFFER_SIZE = SystemInformation.SmallIconSize.Width + 10 ;
			
			MenuItem _menuItem = null ;
			Graphics _graphics = null ;
			ImageList _imageList = null ;
			
			#endregion
			
			#region Constructors
			
			public MenuHelper( MenuItem menuItem, Graphics graphics, ImageList imageList )
			{
				_menuItem = menuItem ;
				_graphics = graphics ;
				_imageList = imageList ;
			}
			
			#endregion
			
			#region Public Members
			
			public int CalcHeight()
			{
				if ( _menuItem.Text == "-" )
					return SEPERATOR_HEIGHT ;
				else
				{
					if ( SystemInformation.MenuFont.Height > SystemInformation.SmallIconSize.Height )
						return SystemInformation.MenuFont.Height + BORDER_SIZE ;
					else
						return SystemInformation.SmallIconSize.Height + BORDER_SIZE ;
				}
			}
			
			public int CalcWidth()
			{
				StringFormat sf = new StringFormat() ;
				sf.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show ;
			
				int menuWidth = (int) _graphics.MeasureString( _menuItem.Text, SystemInformation.MenuFont, 1000, sf).Width ;
				int shortcutWidth = (int) _graphics.MeasureString( this.ShortcutText, SystemInformation.MenuFont, 1000, sf).Width ;
			
				if ( this.IsTopLevel() == true )
					return menuWidth ;
				else
					return IMAGE_BUFFER_SIZE + menuWidth + SHORTCUT_BUFFER_SIZE + shortcutWidth ;
			}
			
			public bool HasShortcut()
			{
				return ( _menuItem.ShowShortcut == true && _menuItem.Shortcut != Shortcut.None ) ;
			}
			
			public bool IsSeperator()
			{
				return ( _menuItem.Text == "-" ) ;
			}
			
			public bool IsTopLevel()
			{
				return ( _menuItem.Parent is MainMenu ) ;
			}
			
			public string ShortcutText
			{
				get
				{
					if ( _menuItem.ShowShortcut == true && _menuItem.Shortcut != Shortcut.None )
					{
						Keys keys = (Keys) _menuItem.Shortcut ;
						return Convert.ToChar(Keys.Tab, CultureInfo.CurrentCulture) + System.ComponentModel.TypeDescriptor.GetConverter(keys.GetType()).ConvertToString(null, CultureInfo.CurrentCulture, keys);
					}
					return null ;
				}
			}

			public void DrawMenu ( Rectangle bounds, bool selected, int indexValue )
			{
				DrawMenuText( bounds, selected ) ;
				
				if ( _menuItem.IsParent == true )
				{
					Image menuImage = null ;
					System.IO.Stream stream = this.GetType().Assembly.GetManifestResourceStream("Chris.Beckett.MenuImageLib.SubItem16.ico") ;
					menuImage = Image.FromStream(stream) ;
					this.DrawArrow( menuImage, bounds ) ;
				}
				
				if ( _menuItem.Checked )
					DrawCheckBox ( bounds ) ;
				else
				{
					if ( indexValue > -1 )
					{
						Image menuImage = null ;
						menuImage = _imageList.Images[indexValue] ;						
						DrawImage( menuImage, bounds ) ;
					}
				}
			}
			
			public void DrawBackground( Rectangle bounds, bool selected )
			{
				if ( selected == true )
					_graphics.FillRectangle(SystemBrushes.Highlight, bounds);
				else
					_graphics.FillRectangle( SystemBrushes.Menu, bounds ) ;
			}
			
			public void DrawSeperator( Rectangle bounds )
			{
				Pen pen = new Pen(SystemColors.ControlDark) ;

				int xLeft = bounds.Left + IMAGE_BUFFER_SIZE ;
				int xRight = xLeft + bounds.Width ;
				int yCenter = bounds.Top  + (bounds.Height / 2) ;

				_graphics.DrawLine(pen, xLeft, yCenter, xRight, yCenter) ;
			}
			
			#endregion
			
			#region Private Members

			private void DrawMenuText ( Rectangle bounds, bool selected )
			{
				Font menuFont = SystemInformation.MenuFont ;
				SolidBrush menuBrush = null ;
				if ( _menuItem.Enabled == false )
					menuBrush = new SolidBrush( SystemColors.GrayText ) ;
				else
				{
					if ( selected == true )
						menuBrush = new SolidBrush( SystemColors.HighlightText ) ;
					else
						menuBrush = new SolidBrush( SystemColors.MenuText ) ;
				}
				
				StringFormat sfMenu = new StringFormat() ;
				sfMenu.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show ;
				_graphics.DrawString( _menuItem.Text, menuFont, menuBrush, bounds.Left + IMAGE_BUFFER_SIZE, bounds.Top + ((bounds.Height - menuFont.Height) / 2), sfMenu ) ;

				if ( this.IsTopLevel() != true || this.HasShortcut() == false )
				{
					StringFormat sfShortcut = new StringFormat() ;
					sfShortcut.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show ;
					sfShortcut.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
					int shortcutWidth = (int) _graphics.MeasureString( this.ShortcutText, menuFont, 1000, sfShortcut).Width ;
					_graphics.DrawString(this.ShortcutText, menuFont, menuBrush, (bounds.Width) - LBUFFER_WIDTH , bounds.Top + ((bounds.Height - menuFont.Height) / 2), sfShortcut);
				}
			}			
			
			private void DrawCheckBox( Rectangle bounds )
			{
				ButtonState btnState = ButtonState.Flat ;
				
				if ( _menuItem.Checked == true )
					btnState = btnState | ButtonState.Checked ;
				
				if ( _menuItem.Enabled == false )
					btnState = btnState | ButtonState.Inactive ;
				
				ControlPaint.DrawCheckBox(_graphics, bounds.Left + SBORDER_WIDTH, bounds.Top + ((bounds.Height - IMAGE_HEIGHT) / 2), IMAGE_WIDTH, IMAGE_HEIGHT, btnState ) ;
			}
			
			private void DrawImage( Image menuImage, Rectangle bounds )
			{
				if ( _menuItem.Enabled == true )
					_graphics.DrawImage(menuImage, bounds.Left + SBORDER_WIDTH, bounds.Top + ((bounds.Height - IMAGE_HEIGHT) / 2), IMAGE_WIDTH, IMAGE_HEIGHT ) ;	
				else
					ControlPaint.DrawImageDisabled(_graphics, menuImage, bounds.Left + SBORDER_WIDTH, bounds.Top + ((bounds.Height - IMAGE_HEIGHT) / 2), SystemColors.Menu ) ;
			}
			
			private void DrawArrow( Image menuImage, Rectangle bounds )
			{
				_graphics.DrawImage(menuImage, bounds.Left + bounds.Width - ARROW_WIDTH, bounds.Top + ((bounds.Height - IMAGE_HEIGHT) / 2), IMAGE_WIDTH, IMAGE_HEIGHT ) ;	
			}
			
			#endregion
		}
		
		#endregion
	}
}
